任務導向對話 (Task-Oriented Dialogue, TOD) 聊天機器人,與一般的 Chatbot 不同,TOD Chatbot 有明確的任務目標,例如點餐、訂票或預約等等。ChatGPT 此類的 LLM 雖然強大,有豐富的知識問答與流暢的文字生成,也能串接一些 API 之類的,但要達成 TOD 其實還是有些難度的。
想要製作一個 TOD 聊天機器人,可以使用 Google Dialogflow, Microsoft Bot Framework, Amazon Lex 等等的服務,但如果你想要從程式碼面親身感受 TOD Chatbot 的運作流程,那 Rasa 是個不錯的選擇。
在 LLM 的時代,大家是如何看待 TOD 這個任務呢?今天就來探討看看相關的研究。
TOD 到底跟一般的對話有哪些不同呢?最大的關鍵在於系統需要從對話裡面擷取實體資訊出來使用。例如一個查詢天氣的機器人,需要從對話中擷取使用者想要詢問哪個地方的天氣?或者是哪個時候的天氣?
Chatbot 可能會從使用者的訊息中擷取類似以下的資訊:
User: 明天台北會下雨嗎?
ParsedSlots:
- Date: 明天
- Location: 台北
- QueryType: 降雨機率
這時 Chatbot 就能透過這些資訊,建構系統發送 HTTP Request 查詢天氣所需要的 API 參數,例如:
https://weather.example/query?date=20231007&location=taipei&query_type=rainy_probability
除此之外,也可能會遇到使用者沒有提供時間的情況,這樣系統是否需要進一步追問?還是有設定預設的時間參數?在 TOD Chatbot 裡面決策流程也是相當重要的一環。
TOD Chatbot 會根據擷取到的實體資訊來採取行動,除了發 HTTP Request 之外,可能也會將客戶的訂單存入資料庫之類的。這時你可能會想,有些 ChatGPT 的插件好像也會做類似的事情欸?
事實上那些插件的確是廣義上的任務導向對話,因為對那些插件來說,他們都有個特定的目的需要執行,且這個任務所需的資訊必須從使用者的對話中取得。
但多數情況下,ChatGPT 的插件主要都在執行單輪對話的任務,但 TOD Chatbot 往往涉及多輪對話,甚至是非常冗長的對話,這在目前輸入長度有限的 LLM 裡面往往是個一大問題。因此在 TOD 裡面,通常會透過記憶狀態來追蹤目前對話的進度如何。
所以 TOD 主要著重在三個面向:實體擷取、決策流程與記憶狀態。
另外像是回覆產生可能也會在 TOD 裡面討論,但多數情況下,開發者可能會更傾向於使用定型範本進行回覆。雖然現在有 LLM 可以產生自然流暢的文字,但如果模型出現幻覺的話就不太好了,尤其是當系統應用涉及金流時更是需要注意。
首先讓我們來關注 Are LLMs All You Need For TOD 這篇論文,這是基於 Instruct LLM 的做法。其實概念相當簡單,傳統 TOD Chatbot 會有領域分類器 (Domain Classifier)、狀態追蹤器 (State Tracker) 與回覆產生器 (Response Generator) 等模組。作者要求 LLM 分別扮演這三個部分來進行對話,例如:
請根據以下對話狀態,決定這是什麼領域。請從以下清單選擇一個領域回答:餐廳、飯店、景點、計程車和火車。只需要回答答案即可,並從清單中選擇最有可能的回答。
=== 範例 1 ===
使用者:我要找一間便宜的餐廳
機器人:我們有很多種便宜的餐廳,請問您對哪種餐廳有興趣呢?
使用者:中式餐廳
領域:餐廳
=== 範例 2 ===
使用者:我要訂兩點的車票
機器人:請問你要從哪裡出發?
使用者:板橋
領域:火車
===
現在完成以下範例:
使用者:我想要在北部找一個便宜的住宿地點
領域:
將以上 Prompt 輸入給 ChatGPT 就能輕鬆獲得「飯店」的答案。類似的概念也能應用在狀態追蹤器上:
請根據對話的最後一句辨識相關實體,以「實體:值」的格式呈現,其中冒號和值之間不應有空格,使用分號(;)分隔不同的實體資訊。如果未指定,則留空該值。應捕捉的值包括:
- 價格:飯店的價格
- 區域:指定飯店所在的區域(東、南、西、北、中)
- 網路:指定飯店是否有網路(是、否)
- 停車場:指定飯店是否有停車場(是、否)
- 星級:指定飯店的星級數(ㄧ、二、三、四、五)
- 類型:指定飯店的類型(飯店、民宿、附早餐)
=== 對話 ===
使用者:我想要在北部找一個便宜的住宿地點
實體:
這樣就能獲得「區域:北;價格:便宜」的結果,在這裡使用的是 Zero-Shot Prompt,因此必須對每個實體進行詳細說明,例如列舉可能的值就是個不錯的辦法。
最後的回覆產生器也是相同的原理:
你現在是個負責預約酒店的客服人員,使用者可以根據酒店名稱、地區、停車場、網路可用性或價格來查詢酒店,請根據資料庫的查詢結果進行回覆。
=== 對話 ===
使用者:我想要在北部找一個便宜的住宿地點
狀態:飯店;區域:北;價格:便宜
查詢結果:酒店數量 23 家
回覆:
將以上 Prompt 丟入 ChatGPT 後,得到的回覆是:「您好!在北部地區,我為您找到了 23 家價格較為便宜的酒店。請問您需要我列出其中幾家供您參考,或是有其他特定的需求嗎?」。
透過簡單的 Zero-Shot/Few-Shot Instruction Prompt,就能建構起一個 LLM-Based TOD Chatbot 了。從論文作者的實驗數據來看,這樣的做法不只 ChatGPT 有用,在 Alpaca 7B 模型上也能見效。但我想應該是指英文的情況下,中文的部份可能還需要等待一個更好的小模型,這個做法才能在 7B 這種規模上應用。
其中在建構 Few-Shot Prompt 的部份,這篇論文也應用了 Retrieval 的技巧,來尋找相關的範例放進 Prompt 裡面,可以提昇辨識的準確率。
(圖源:Are LLMs All You Need For TOD?)
Rasa 是個開源的聊天機器人開發框架,在 GitHub 上可以看到這是個從 2016 年發起的專案,算是個有一定年紀的框架了。
Rasa 直到現在都還是非常活躍的專案,而最近能夠從官方文件上看到一些與 LLM 整合的蛛絲馬跡,目前看起來這應該會是付費版 Rasa 的功能,但是從這些說明文件,我們還是可以瞭解其運作原理。
在官方文件上的架構圖,與方才介紹的論文是有些異曲同工之妙的,他們同樣使用了 Retrieval-Based 的方法來建構 Prompt 輸入,同樣藉由 LLM Few-Shot 的能力來進行各個階段的辨識。
(圖源:Rasa 官方文件)
在意圖辨識的部分,官方給了一個 Prompt 範例:
Label a users message from a
conversation with an intent. Reply ONLY with
the name of the intent.
The intent should be one of the following:
- affirm
- greet
Message: Hello
Intent: greet
Message: Yes, I am
Intent: affirm
Message: hey there
Intent:
同樣也是一段 Instruction 搭配幾個 Few-Shot 範例,然後請 LLM 回答分類結果。而在 NLG 部份,Rasa 的做法就與方才的論文有些不同了:
The following is a conversation with an AI assistant. The assistant is helpful, creative, clever, and very friendly. Rephrase the suggest AI response staying close to the original message and retaining
its meaning. Use simple english.
Context / previous conversation with the user:
{{history}}
{{current_input}}
Suggested AI Response: {{suggested_response}}
Rephrased AI Response:
從這個 Prompt Template 可以看出,系統會先給一段「建議的回覆」,然後再請 LLM 做改寫。這也是個相當值得參考的做法,不管是 Few-Shot Examples 或這種給建議做改寫的方法,其核心價值都是要給 LLM 一個參考的基準。
有趣的是 Rasa 提出了另外一種 Intentless Policy 的做法,在 TOD Chatbot 裡面決策 (Policy) 是用來根據對話狀態判斷需要採取什麼動作的模組。例如現在使用者在打招呼,那 Policy 可能就會決定回覆一個打招呼的訊息;使用者下了一個訂單,那 Policy 可能會決定呼叫一個 API 跟資料庫互動等等。
多數的情況都可以透過規則式決策來處理,但最麻煩的是出現一些系統意料之外的狀況,這時 Chatbot 到底該如何做回應呢?這部分其實區分成兩個概念,第一個是系統如何偵測意料之外的情況發生了,第二個就是如何應對這個意料之外的情況。
透過官方文件並沒有辦法很明確的知道這個環節到底是如何跟 LLM 進行互動的,但是從官方提供的範例專案可以猜出一些蛛絲馬跡。
首先是這個範例的 NLU 幾乎沒有特別重要的範例,只包含了一些打招呼之類的意圖而已。看起來是完全靠 End-To-End 劇本來處理大部分的對話流程。
再來觀察官方文件提供的範例:
可見 Intentless Policy 主打 Contextual Response 的特性,因此做法大致上是將前幾回合的對話內容輸入 LLM 請他判斷應該如何回覆。另外根據官方文件所述,這個功能並不會生成新的回覆,也就是說回覆都是從預先定義好的句子裡面挑選的,所以筆者對 Prompt 的臆測大致如下:
你是一個專業的銀行客服,請根據對話內容挑選適當的回覆。
回覆 A:您可以使用手機 App 進行匯款。
回覆 B:您可以攜帶雙證件與存簿臨櫃辦理。
回覆 C:很抱歉,我幫不上忙。
=== 範例 1 ===
使用者:有沒有零手續費的匯款方式
機器人:回覆 A
=== 範例 2 ===
使用者:我沒有手機該如何匯款
機器人:回覆 B
=== 對話 ===
使用者:匯款可不可以不要手續費
機器人:回覆 A
使用者:可是我手機壞了
機器人:
把以上 Prompt 丟進 ChatGPT 測試,可以獲得「回覆 B」的答案,看起來是可行的。根據官方文件所述,這應該是個閉源的功能,所以實際的 Prompt 到底如何建構,目前也無從得知,這裡筆者只是提供一個方向給大家參考。
另外,Rasa 特別提到他們使用 Jinja 這個套件進行 Prompt Template 的編寫,這也是值得參考的部份。
在 LLM 出現之前,Rasa 已經算是個發展成熟的框架了,基本元件使用起來相當靈活,官方文件的內容也相當豐富,也有進一步的商業版可用。現在加入強大的 LLM 之後,辨識率、跨語言等都不再是個問題,相信在 TOD 這領域上未來可期。
這個章節只是個小補充,在接觸 TOD Chatbot 的過程中,可能會去研究 Google 的 Dialogflow 框架。雖然這個框架主要是使用 BERT 模型建立的,但因為功能相當完整,所以依然是個不錯的選擇。
而 Dialogflow 其實還區分成 ES 跟 CX 兩種版本,其中 ES 是比較簡單的版本,而 CX 是比較複雜的版本。如果是沒有接觸過 TOD 的朋友,可能可以考慮先從 ES 開始研究,否則可能會被 CX 的文件給嚇到。
目前在 TOD Chatbot 領域,似乎還沒看到相對實際的應用出現。但無論是學界還是業界,都不斷提出基於 LLM 的做法,而其核心概念幾乎都是相似的,透過 Instruction 來指示 LLM 扮演傳統 TOD 系統的某個元件,並結合 Retrieval-Base 的做法,來取代原本需要訓練的模型。因為 LLM 本身的高泛用性且跨語言的特質,使原本有些瓶頸的傳統做法看見了一線曙光。
有沒有發現,最近關於 LLM 的文章,三句不離 Retrieval 這個單字!筆者認為,即便未來 LLM 沒有輸入上限問題,檢索方法依然會相當受用,因為他確實能讓模型產生更精確的回覆,所以資訊檢索這領域也許會再次得到重視。